<script setup lang="ts">
import {
  computed,
  markRaw,
  reactive,
  ref,
  shallowReactive,
  shallowRef,
  toRef,
  toRefs,
  watch,
  watchEffect,
} from 'vue'
// ref()
const count = ref(0)
const user = ref({
  name: 'lx',
  age: 18,
})
const items = ref([1, 2, 3])
console.log(count.value)
console.log(user.value)
console.log(items.value)

// reactive()
const state = reactive({
  count: 0,
  message: 'Hello World',
  user: {
    name: 'lx',
    age: 18,
  },
  items: [1, 2, 3],
})
state.count = 1
state.user.age = 23
state.items[0] = 4
console.log('state', state)

// computed()
const firstName = ref('li')
const lastName = ref('xiao')
const fullName = computed(() => firstName.value + ' ' + lastName.value)

// 可读可写的计算属性
const firstName2 = ref('John')
const lastName2 = ref('Doe')
const fullName2 = computed({
  get: () => firstName2.value + ' ' + lastName2.value,
  set: (value) => {
    const names = value.split(' ')
    firstName2.value = names[0]
    lastName2.value = names[1]
  },
})

fullName2.value = 'Jane Smith'
console.log('firstName2', firstName2.value, 'lastName2', lastName2.value)

// watch() 和 watchEffect()
const message = ref('Hello World')
// watch - 监听特定数据源
watch(message, (newValue, oldValue) => {
  console.log(`message 从 ${oldValue} 变为 ${newValue}`)
})

// 监听多个数据源
watch([count, message], ([newCount, newMessage], [oldCount, oldMessage]) => {
  console.log('数据发生变化:', { newCount, newMessage, oldCount, oldMessage })
})

// watch - 监听对象属性
watch(
  () => state.user.age,
  (newUser, oldUser) => {
    console.log('用户信息已更新:', { newUser, oldUser })
  },
)

// watch 选项
watch(
  () => state.user,
  (newUser, oldUser) => {
    console.log('用户信息已更新222:', { newUser, oldUser })
  },
  {
    deep: true,
    immediate: true,
    once: true,
  },
)

// watchEffect - 自动追踪依赖
watchEffect(() => {
  console.log(`当前计数: ${count.value}, 消息: ${message.value}`)
})

// 立即执行
watchEffect(
  () => {
    console.log('立即执行')
  },
  { flush: 'post' },
)

// watchEffect - 停止监听
const stop = watchEffect(() => {
  console.log(`当前计数1111: ${count.value}, 消息: ${message.value}`)
})
stop()

// 响应式工具函数: isRef、unref、toRef、toRefs
// isRef - 检查一个值是否为 ref 对象
// unref - 如果一个值是 ref 对象，则返回它的 value，否则返回这个值本身
// toRef - 创建一个 ref 对象，其 value 属性指向源对象中的某个属性
const obj = { a: 1 }
const a = toRef(obj, 'a')
a.value = 2 // 修改 ref 会同步到原对象
console.log('obj----------------------', obj)
// toRefs - 创建一个对象，其属性指向源对象中的某个属性
const stateToRefs = reactive({
  count: 0,
  message: 'Hello',
})

const { count: count2, message: message2 } = toRefs(stateToRefs)
console.log('count, message', count2, message2)

// shallowRef和shallowReactive
// shallowRef - 创建一个 ref 对象，其 value 属性指向一个普通值
const stateRef = ref({ count: 1 }) // 深度响应式
const shallowState = shallowRef({ count: 1 }) // 浅层响应式

// 修改内部属性 - ref 会触发响应
stateRef.value.count = 2 // 触发更新

// 修改内部属性 - shallowRef 不会触发响应
shallowState.value.count = 2 // 不会触发更新

// 替换整个值 - 两者都会触发响应
shallowState.value = { count: 2 } // 触发更新

// shallowReactive - 创建一个不需要深度响应式的数据
const deepState = reactive({
  nested: {
    count: 1,
  },
}) // 深度响应式

const shallowRState = shallowReactive({
  nested: {
    count: 1,
  },
}) // 浅层响应式

// 修改嵌套属性 - reactive 会触发响应
deepState.nested.count = 2 // 触发更新

// 修改嵌套属性 - shallowReactive 不会触发响应
shallowRState.nested.count = 2 // 不会触发更新

// 修改第一层属性 - 两者都会触发响应
shallowRState.nested = { count: 2 } // 触发更新

// markRaw - 标记一个对象，使其永远不会转换为响应式
const rawObj = markRaw({
  name: 'raw',
  age: 30,
}) // 创建一个不需要响应式的对象
console.log('rawObj', rawObj)
</script>

<template>
  <div class="reactivity">
    <h1>响应式系统</h1>
    <div>
      <h2>ref和reactive</h2>
      <div>count is: {{ count }}</div>
      <button @click="count++">+</button>
    </div>
    <br />
    <div>
      <h2>计算属性</h2>
      <div>
        <label for="firstName">FirstName: </label>
        <input id="firstName" v-model="firstName" />
      </div>
      <div :style="{ marginTop: '10px' }">
        <label for="lastName">LastName: </label>
        <input id="lastName" v-model="lastName" />
      </div>
      <div>FullName: {{ fullName }}</div>
    </div>
    <br />
    <div>
      <h2>watch和watchEffect</h2>
      <input type="text" v-model="message" />
      <div>
        <button @click="state.user.age = 26">更新</button>
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss"></style>
